package org.example.gateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.example.gateway.config.JwtConfig;
import org.example.model.manage.bean.po.security.MyUserDetails;
import org.springframework.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class JwtAuthFilter implements GatewayFilter {

    private final JwtConfig jwtConfig;
    private final ReactiveStringRedisTemplate reactiveStringRedisTemplate;
    private final ObjectMapper objectMapper;

    // 构造函数注入
    @Autowired
    public JwtAuthFilter(JwtConfig jwtConfig, ReactiveStringRedisTemplate reactiveStringRedisTemplate, ObjectMapper objectMapper) {
        this.jwtConfig = jwtConfig;
        this.reactiveStringRedisTemplate = reactiveStringRedisTemplate;
        this.objectMapper = objectMapper;
    }

    // 路径常量
    private static final String LOGIN_PATH = "/user/login";
    private static final String STUDENT_PATH_PREFIX = "/student/";
    private static final String LISTEN_PATH_PREFIX = "/listen/";
    private static final String REDIS_JWT_KEY_PREFIX = "login:";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        
        log.info("JWT Auth Filter processing path: {}", path);
        
        String jwtSecret = jwtConfig.getSecret();
        long jwtExpiration = jwtConfig.getExpireTime();
        
        log.info("JWT secret loaded: {}, JWT expire time: {}", 
                jwtSecret != null ? "YES" : "NO", jwtExpiration);

        // 放行不需要JWT验证的路径
        if (path.equals(LOGIN_PATH) || path.startsWith(STUDENT_PATH_PREFIX) || path.startsWith(LISTEN_PATH_PREFIX)) {
            log.info("Path {} is whitelisted, proceeding without JWT validation", path);
            return chain.filter(exchange);
        }

        // 检查JWT配置是否正确加载
        if (!StringUtils.hasText(jwtSecret)) {
            log.error("JWT secret is not properly configured!");
            return unauthorizedResponse(exchange, "JWT配置错误");
        }

        // 从请求头中获取token
        String token = request.getHeaders().getFirst("Authorization");
        log.info("Authorization header: {}", token != null ? "present" : "missing");

        if (token == null || !token.startsWith("Bearer ")) {
            log.warn("No valid Authorization header found for path: {}", path);
            return unauthorizedResponse(exchange, "未提供有效的token");
        }

        // 提取token
        token = token.substring(7);
        String finalToken = token;

        try {
            // 使用auth0库验证token
            Algorithm algorithm = Algorithm.HMAC256(jwtSecret.getBytes(StandardCharsets.UTF_8));
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            log.info("JWT token validated successfully for user");

            // 从claim中获取用户ID
            Map<String, Object> claim = jwt.getClaim("claim").asMap();
            if (claim == null || claim.get("id") == null) {
                log.warn("JWT claim is missing or invalid");
                return unauthorizedResponse(exchange, "JWT claim无效");
            }
            
            String userId = claim.get("id").toString();
            String redisKey = REDIS_JWT_KEY_PREFIX + userId;
            log.info("Checking Redis for user: {}, key: {}", userId, redisKey);

            // 检查Redis中的token是否有效
            return reactiveStringRedisTemplate.opsForHash().get(redisKey, "jwt")
                    .defaultIfEmpty("")
                    .flatMap(redisToken -> {
                        String tokenStr = redisToken.toString();
                        
                        // 检查token是否为空
                        if (!StringUtils.hasText(tokenStr)) {
                            log.warn("Redis token is empty for user: {}", userId);
                            return unauthorizedResponse(exchange, "token已过期或无效");
                        }
                        
                        // 处理Redis返回的字符串格式（可能包含引号）
                        if (tokenStr.startsWith("\"") && tokenStr.endsWith("\"")) {
                            tokenStr = tokenStr.substring(1, tokenStr.length() - 1);
                        }
                        
                        if (!tokenStr.equals("Bearer " + finalToken)) {
                            log.warn("Redis token validation failed for user: {}", userId);
                            return unauthorizedResponse(exchange, "token已过期或无效");
                        }

                        log.info("Redis token validation successful for user: {}", userId);

                        // 从Redis获取用户信息
                        return reactiveStringRedisTemplate.opsForHash().get(redisKey, "user")
                                .flatMap(userStr -> {
                                    log.info((String) userStr);
                                    if (userStr == null || !StringUtils.hasText(userStr.toString())) {
                                        log.warn("User info not found in Redis for user: {}", userId);
                                        return unauthorizedResponse(exchange, "用户信息不存在");
                                    }

                                    try {
                                        // 将字符串转换为MyUserDetails
                                        String userString = userStr.toString();
                                        MyUserDetails userDetails = objectMapper.readValue(userString, MyUserDetails.class);

                                        log.info("User info parsed successfully for user: {}", userId);

                                        // 传递用户信息给下游服务，包括用户信息供权限过滤器使用
                                        ServerHttpRequest modifiedRequest = request.mutate()
                                                .header("user-id", userId)
                                                .header("Authorization", "Bearer " + finalToken)
                                                .header("user-info", userString)  // 添加用户信息到请求头
                                                .build();
                                        return chain.filter(exchange.mutate().request(modifiedRequest).build());
                                    } catch (Exception e) {
                                        log.error("Error parsing user info for user: {}", userId, e);
                                        return unauthorizedResponse(exchange, "用户信息解析失败: " + e.getMessage());
                                    }
                                });
                    })
                    .onErrorResume(e -> {
                        log.error("Redis validation error for user: {}", userId, e);
                        return unauthorizedResponse(exchange, "Redis验证失败: " + e.getMessage());
                    });

        } catch (TokenExpiredException e) {
            log.warn("JWT token expired for path: {}", path);
            return unauthorizedResponse(exchange, "token已过期");
        } catch (JWTVerificationException e) {
            log.warn("JWT verification failed for path: {}", path, e);
            return unauthorizedResponse(exchange, "无效的token");
        } catch (Exception e) {
            log.error("Unexpected error in JWT filter for path: {}", path, e);
            return unauthorizedResponse(exchange, "JWT验证异常: " + e.getMessage());
        }
    }

    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

        Map<String, Object> responseBody = new HashMap<>();
        responseBody.put("code", HttpStatus.UNAUTHORIZED.value());
        responseBody.put("message", message);

        String json;
        try {
            json = objectMapper.writeValueAsString(responseBody);
        } catch (JsonProcessingException e) {
            json = "{\"code\": 500, \"message\": \"服务器内部错误\"}";
        }

        return response.writeWith(Mono.just(response.bufferFactory().wrap(json.getBytes())));
    }
}